/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package edu.pdx.cs.guavadata.data;

import edu.pdx.cs.guavadata.Transaction;
import edu.pdx.cs.guavadata.domain.Domain;
import edu.pdx.cs.guavadata.query.AddTable;
import edu.pdx.cs.guavadata.query.Command;
import edu.pdx.cs.guavadata.query.ForeignKey;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author VuTran
 */
public class Scheme {
    private String tableName;

    public Schema container;
    public List<Column> columns;
    public Scheme parent;
    public List<Column> pkColumns;
    public List<Column> fkColumns;
    public List<String> children;

    public Scheme(String name, Scheme parent) {
        this.tableName = name;
        this.parent = parent;
        columns = new ArrayList<Column>();
        pkColumns = new ArrayList<Column>();
        fkColumns = new ArrayList<Column>();
        children = new ArrayList<String>();
    }

    public Column newColumn(String name, Domain type, boolean pk, boolean fk) {
        Column temp = new Column(name, type);
        this.columns.add(temp);
        if (pk) this.pkColumns.add(temp);
        if (fk) this.fkColumns.add(temp);
        return temp;
    }

    public String getPkString() {
        String build = "";

        if (pkColumns.size() <= 0) return build;

        boolean first = true;
        for (Column column : pkColumns) {
            if (first)
                build += column.getColumnName();
            else
                build += ", " + column.getColumnName();
            first = false;
        }

        return build;
    }

    public String getFkString() {
        String build = "";

        if (fkColumns.size() <= 0) return build;

        boolean first = true;
        for (Column column : fkColumns) {
            if (first)
                build += column.getColumnName();
            else
                build += ", " + column.getColumnName();
            first = false;
        }

        return build;
    }

    @Override
    public String toString() {
        String build = null;
        try {
            if (columns.size() <= 0) {
                throw new Exception("Cannot create table " + tableName + " with no columns.");
            }
            if (pkColumns.size() <= 0) {
                throw new Exception("Cannot create table " + tableName + " with no columns.");
            }
            build = "CREATE TABLE " + this.tableName + " (";

            //define columns with their assocaited data types
            for (Column column : columns)
                build += column.toString() + ", ";

            // add primary key
            if (getPkString().equals("")) 
                build += "CONSTRAINT pk_" + this.tableName + " PRIMARY KEY CLUSTERED (" + getPkString() + ")";

            // Add foreign key, if only one parent
            Scheme sParent = null;
            for (Scheme sTemp : this.container.tables)
            {
                if (sTemp.children.contains(this.tableName))
                {
                    if (sParent == null) sParent = sTemp;
                    else return build + ")";
                }
            }

            if (sParent != null)
            {
                // We also have a foreign key to create
                build += ", CONSTRAINT fk_" + this.tableName + " FOREIGN KEY (" + getFkString() + ") REFERENCES ";
                build += sParent.tableName + " (" + sParent.getPkString() + ") ON DELETE CASCADE ON UPDATE CASCADE";
            }

            build += ")";

        } catch (Exception ex) {
            System.err.println("ERROR: " + ex.toString());
        }

        return build;
    }

    public void appendTransaction(Transaction t) {
        // create the add table statement
        AddTable at = new AddTable(this.tableName);

        for (Column c : columns) {
            at.addColumn(c.getColumnName(), c.dom, pkColumns.contains(c));
        }

        // add the create table statement, if the table does not exist yet
        boolean found = false;
        for (Command c : t.getContents())
            if (c.root instanceof AddTable)
                if (((AddTable) c.root).getTable().equals(this.tableName))
                    found = true;

        if (!found) {
            t.add(new Command(at));
        }

        // create the foreign key statement, if necessary
        if (fkColumns.size() > 0 && parent != null) {
            // Dummy check - number of fk columns matches the number of pk columns in parent (required in view model, not within channel)
            if (fkColumns.size() != parent.pkColumns.size())
                try {
                throw new Exception("Number of foreign key columns does not match number of primary key columns in the parent table.");
            } catch (Exception ex) {
                Logger.getLogger(Scheme.class.getName()).log(Level.SEVERE, null, ex);
            }

            ForeignKey fk = new ForeignKey(this.tableName, parent.getTableName());
            for (int i = 0; i < fkColumns.size(); i++)
                fk.addColumn(fkColumns.get(i).getColumnName() , parent.pkColumns.get(i).getColumnName());

            // Add foreign key statement to transaction
            t.add(new Command(fk));
        }
    }

    /**
     * @return the tableName
     */
    public String getTableName() {
        return tableName;
    }

    /**
     * @param tableName the tableName to set
     */
    public void setTableName(String tableName) {
        this.tableName = tableName;
    }


}
